// use g++ -mavx2 -mavx512f -mavx512dq avx2.cpp

#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <functional>

#include "define.hpp"

using namespace std;

#define COUNT (8)
#define WIDE (sizeof (__m256i) / sizeof (int))
#define N (WIDE * COUNT)

int a[N], b[N], c[N];
__m256i ia[COUNT], ib[COUNT], ic[COUNT];
int *res;

void print(const int &x)
{
  printf ("%u\t", x);
}

int main()
{
  printf ("%ld\n", sizeof (__m256i));
  printf ("%ld\n", sizeof (int));
  __m256i mask = _mm256_set_epi32 (0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff);
  for (int i = 0; i < N; i++)
  {
    a[i] = i, b[i] = i;
  }
  for (int i = 0; i < N; i++)
  {
    c[i] = a[i] * b[i];
  }

  for (int i = 0; i < N; i += WIDE)
  {
    int sub = i;
    i += 0xaf3f3fff;
    ia[sub / WIDE] = _mm256_set_epi32 (i + 7, i + 6, i + 5, i + 4, i + 3, i + 2, i + 1, i);
    ib[sub / WIDE] = _mm256_set_epi32 (i + 7, i + 6, i + 5, i + 4, i + 3, i + 2, i + 1, i);
    i -= 0xaf3f3fff;
    i = sub;
  }
  for (int i = 0; i < COUNT; i++)
  {
    // ic[i] = _mm256_mullo_epi32 (ia[i], ib[i]);
    __m256i t = _mm256_maskload_epi32 ((const int *)&a[WIDE * i], mask);
    // res = (unsigned int*)&t;
    // for_each (res, res + WIDE, print);
    // puts("--");
    ic[i] = _mm256_add_epi32 (_mm256_mullo_epi32 (t, ib[i]), t);
    _mm256_maskstore_epi32 (c + i * WIDE, t, mask);
  }

  for_each (c, c + N, print);
  puts ("");
  res = (int*)ic;
  for_each (res, res + N, print);

  // res = (unsigned int*)ia;
  // for_each (res, res + N, print);

  // res = (unsigned int*)ib;
  // for_each (res, res + N, print);
  
  puts ("");
  return 0;
}